package UI

import (
	"errors"
	"github.com/eiannone/keyboard"
	"math"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"
)

// 通用常量
const (
	Auto                int    = math.MaxInt      //用于提高可读性，无实际作用
	SizeReLoadFrequency uint16 = 10               //窗口查询的频率,此为x ms
	BodyName                   = "body"           //顶级节点的Name，顶级节点的Name是固定的，但Name为body的节点可能不只有body，获取body时，建议通过全局变量而非GetNodeByName函数
	QuadrilateralTag           = "quadrilateral"  //不同类型Node的Tag，此处为四边形
	ZIndexRenderType    uint8  = 0                //不同渲染器的类型，它可以通过层级获取Node
	PackageName                = "TMLRenderer"    //包名，一般用于信息打印
	RenderLazy                 = time.Microsecond //异步等待时间
)

// 通用变量
var (
	SysWidth           int                  = 0     //全局宽度
	SysHeight          int                  = 0     //全局高度
	isInit             bool                 = false //是否进行初始化
	quadrilateralStore sync.Map                     //四边形存储的库 Key:string value:Node
	nameLibrary        map[string]NodeStack         //以名称分类的结点库
	Body               Node                 = nil   //根节点
	zIndexStack        sync.Map                     //渲染层级 Key:uint32 指index层级  value:NodeStack 其层级存储的结点
	DefaultStyle       = CanvasStyle{       //创建节点的默认样式
		Display:         true,
		BorderType:      None,
		AutoSize:        false,
		ShowText:        true,
		Color:           WhiteColor,
		BackGroundColor: BlackBackGroundColor,
	}
	globalBuf  = strings.Builder{} //最终打印的V100数据
	eventStore sync.Map            //事件存储，为了防止线程冲突，使用sync.map映射map[string]Event{}
	SelectNode Node                = nil
)

// style相关常量
const (
	None            uint8 = 0 //通常表示此样式无效
	ContinuousLine  uint8 = 1 //连续的线
	DottedLine      uint8 = 2 //虚线
	PositionX       uint8 = 1 //用于Position中的x居中
	PositionY       uint8 = 2 //用于Position中的y居中
	PositionXY      uint8 = 3 //用于Position中的x、y居中
	PositionRightX  uint8 = 4 //x基于右侧对齐
	PositionRightY  uint8 = 5 //y基于下侧对齐
	PositionRightXY uint8 = 6 //xy分别对于右下对其
)

// 错误信息常量
const (
	OperatingEmptyNodeError           = "you are trying to operate a node that has been unmounted node"
	DeleteTopLeveNodeError            = "you are trying to delete a top-level node, which is not allowed to be destroyed"
	WrongCursorMovementDirectionError = "incorrect cursor movement. Please check the writing specification"
	RenderUninitializedNodeError      = "trying to render an uninitialized node"
	GetWindowSizeError                = "an attempt to get the window size failed, causing the framework to fail: "
	ParentNodeNil                     = "The parent node is nil, and setting the parent node to nil may cause the cursor to reset"
)

// VT100专用
const (
	vT100Basics                = "\033["
	closeAllProperties         = "\033[0m" //关闭所有属性
	highlight                  = "\033[1m" //设为高亮
	underline                  = "\033[4m" //下划线
	flicker                    = "\033[5m" //闪烁
	backDisplay                = "\033[7m" //反显示
	blanking                   = "\033[8m" //消隐
	left                  byte = 'D'
	right                 byte = 'C'
	top                   byte = 'A'
	bottom                byte = 'B'
	clearScreen                = "\033[2J"   //清屏
	clearTheCursorEnd          = "\033[K"    //清除从光标到行尾的内容
	saveCursor                 = "\033[s"    //保存光标位置
	restoreCursor              = "\033[u"    //恢复光标位置
	hiddenCursor               = "\033[?25l" //隐藏光标
	showCursor                 = "\033[?25h" //显示光标
	BlackColor                 = "\033[30m"  //黑色
	RedColor                   = "\033[31m"  //红色
	GreenColor                 = "\033[32m"  //绿色
	YellowColor                = "\033[33m"  //黄色
	BlueColor                  = "\033[34m"  //蓝色
	PurpleColor                = "\033[35m"  //紫色
	CyanColor                  = "\033[36m"  //青色
	WhiteColor                 = "\033[37m"  //白色
	BlackBackGroundColor       = "\033[40m"  //黑背景色
	RedBackGroundColor         = "\033[41m"  //红背景色
	GreenBackGroundColor       = "\033[42m"  //绿背景色
	YellowBackGroundColor      = "\033[43m"  //黄背景色
	BlueBackGroundColor        = "\033[44m"  //蓝背景色
	PurpleBackGroundColor      = "\033[45m"  //紫背景色
	CyanBackGroundColor        = "\033[46m"  //青背景色
	WhiteBackGroundColor       = "\033[47m"  //白背景色
)

// 事件专用常量
const (
	OnMove       uint8 = 0
	OnSizeChange uint8 = 1
	OnShow       uint8 = 2
	OnHidden     uint8 = 3
	OnInput      uint8 = 4
	OnRemove     uint8 = 5
	OnSelect     uint8 = 6
	OnKeyBord    uint8 = 7
)

type Key uint16

// Keycode
const (
	KeyF1 keyboard.Key = 0xFFFF - iota
	KeyF2
	KeyF3
	KeyF4
	KeyF5
	KeyF6
	KeyF7
	KeyF8
	KeyF9
	KeyF10
	KeyF11
	KeyF12
	KeyInsert
	KeyDelete
	KeyHome
	KeyEnd
	KeyPgup
	KeyPgdn
	KeyArrowUp
	KeyArrowDown
	KeyArrowLeft
	KeyArrowRight
	key_min // see terminfo
)

const (
	KeyCtrlTilde      keyboard.Key = 0x00
	KeyCtrl2          keyboard.Key = 0x00
	KeyCtrlSpace      keyboard.Key = 0x00
	KeyCtrlA          keyboard.Key = 0x01
	KeyCtrlB          keyboard.Key = 0x02
	KeyCtrlC          keyboard.Key = 0x03
	KeyCtrlD          keyboard.Key = 0x04
	KeyCtrlE          keyboard.Key = 0x05
	KeyCtrlF          keyboard.Key = 0x06
	KeyCtrlG          keyboard.Key = 0x07
	KeyBackspace      keyboard.Key = 0x08
	KeyCtrlH          keyboard.Key = 0x08
	KeyTab            keyboard.Key = 0x09
	KeyCtrlI          keyboard.Key = 0x09
	KeyCtrlJ          keyboard.Key = 0x0A
	KeyCtrlK          keyboard.Key = 0x0B
	KeyCtrlL          keyboard.Key = 0x0C
	KeyEnter          keyboard.Key = 0x0D
	KeyCtrlM          keyboard.Key = 0x0D
	KeyCtrlN          keyboard.Key = 0x0E
	KeyCtrlO          keyboard.Key = 0x0F
	KeyCtrlP          keyboard.Key = 0x10
	KeyCtrlQ          keyboard.Key = 0x11
	KeyCtrlR          keyboard.Key = 0x12
	KeyCtrlS          keyboard.Key = 0x13
	KeyCtrlT          keyboard.Key = 0x14
	KeyCtrlU          keyboard.Key = 0x15
	KeyCtrlV          keyboard.Key = 0x16
	KeyCtrlW          keyboard.Key = 0x17
	KeyCtrlX          keyboard.Key = 0x18
	KeyCtrlY          keyboard.Key = 0x19
	KeyCtrlZ          keyboard.Key = 0x1A
	KeyEsc            keyboard.Key = 0x1B
	KeyCtrlLsqBracket keyboard.Key = 0x1B
	KeyCtrl3          keyboard.Key = 0x1B
	KeyCtrl4          keyboard.Key = 0x1C
	KeyCtrlBackslash  keyboard.Key = 0x1C
	KeyCtrl5          keyboard.Key = 0x1D
	KeyCtrlRsqBracket keyboard.Key = 0x1D
	KeyCtrl6          keyboard.Key = 0x1E
	KeyCtrl7          keyboard.Key = 0x1F
	KeyCtrlSlash      keyboard.Key = 0x1F
	KeyCtrlUnderscore keyboard.Key = 0x1F
	KeySpace          keyboard.Key = 0x20
	KeyBackspace2     keyboard.Key = 0x7F
	KeyCtrl8          keyboard.Key = 0x7F
)

// cursorMovement 控制光标移动
// @parma direction: 方向，详细请见常量, step: 移动的步距
// @return 最终的VT100样式
func cursorMovement(direction byte, step uint32) string {
	if direction != left && direction != right && direction != top && direction != bottom {
		throw(WrongCursorMovementDirectionError)
	}
	strBuff := strings.Builder{}
	strBuff.WriteString(vT100Basics)
	strBuff.WriteString(strconv.Itoa(int(step)))
	strBuff.WriteByte(direction)
	return strBuff.String()
}

// setCursorPosition 设置光标位置
// @parma x: x轴位置 y: y轴位置
// @return 最终的VT100样式
func setCursorPosition(x, y uint32) string {
	strBuff := strings.Builder{}
	strBuff.WriteString(vT100Basics)
	strBuff.WriteString(strconv.Itoa(int(y)))
	strBuff.WriteByte(';')
	strBuff.WriteString(strconv.Itoa(int(x)))
	strBuff.WriteByte('H')
	return strBuff.String()
}

// CanvasPosition canvas的位置信息，以及其权重
type CanvasPosition struct {
	X      int                //x轴位置
	Y      int                //y轴位置
	totalX int                //包括自身x和其所有上级节点的x偏移，任何组件都应该在可渲染的情况下更新此属性，此属性对大部分childNode至关重要
	totalY int                //包括自身y和其所有上级节点的y偏移
	Type   CanvasPositionType //不同position类型，比如居中显示
	ZIndex uint32             //权重，越高则显示的优先级越高，权重高的canvas会覆盖权重低的（仅在同级有效）
}

// CanvasPositionType position所表示的类型
type CanvasPositionType struct {
	Center uint8
	Right  uint8
}

type NodeStack []Node

// CanvasVolume 描述canvas的体积参数
type CanvasVolume struct {
	Width  int //宽度
	Height int //高度
}

// CanvasStyle 描述样式
type CanvasStyle struct {
	Display         bool   //是否显示，并非删除
	AutoSize        bool   //自适应大小，其大小继承父元素，在volume的width\height不等于0时会被有效值覆盖
	BorderType      uint8  //是否显示border，以及
	BorderColor     string //边框颜色
	Color           string //文本颜色
	BackGroundColor string //背景颜色
	ShowText        bool   //是否显示文字
}

// Canvas 画布主体
type Canvas struct {
	name     string         //用作识别，但是不唯一
	tag      string         //标签
	key      string         //唯一的key
	position CanvasPosition //位置及权重信息
	volume   CanvasVolume   //体积信息
	style    CanvasStyle    //样式
	parent   Node           //父节点
	children []Node         //子节点
	unMount  bool           //是否卸载
	text     string         //Node需要渲染的文本数据，在可以显示的情况下应该尽可能地展示全面

}

// CanvasAttr Canvas的一些关键信息
type CanvasAttr struct {
	Name string //Node的名称
	Tag  string //Node的类型
	Key  string //Node的唯一标识
}

// Quadrilateral 正方形的Canvas
type Quadrilateral struct {
	Canvas                     //继承的struct
	keyboard.KeyEvent          //存储key bord事件产生的数据
	props             sync.Map //存放自定义信息的props
}

// EventCallBack 回调函数类型
type EventCallBack func(node Node, origen Node)

type Event = map[uint8][]EventCallBack

// Node 元素要实现的公用接口
type Node interface {
	Insert(node ...Node) error                                              //向当前结点中插入元素
	SetVolume(volume CanvasVolume) error                                    //通过Volume字段设置体积
	SetPosition(position CanvasPosition, pType ...CanvasPositionType) error //设置Position字段相关属性
	SetStyle(style CanvasStyle) error                                       //设置Style相关属性
	GetVolume() (CanvasVolume, error)                                       //返回当前node的相关体积
	GetPosition() (CanvasPosition, error)                                   //获取Position字段相关信息
	GetStyle() (CanvasStyle, error)                                         //获取样式
	GetProps() (map[string]string, error)                                   //获取Props
	SetProps(key, value string) error                                       //设置Props自定义字段
	GetKeyBord() (keyboard.KeyEvent, error)                                 //尝试获取当前节点的键盘事件值(只有在事件中获取才会准确)
	AddEventListener(event uint8, callback EventCallBack) error             //添加事件监听
	DeleteEventListener(event uint8, callback EventCallBack) error          //删除事件监听
	GetAttr() (CanvasAttr, error)                                           //获取Attr字段相关信息
	RemoveChildren(node Node) error                                         //删除某一个子节点
	GetParent() (Node, error)                                               //获取父节点
	GetChildren() ([]Node, error)                                           //获取所有子节点
	isUnMount() bool                                                        //检查是否卸载
	Remove() error                                                          //自我删除
	setParent(node Node) error                                              //设置Node的父节点
	SetText(text string) error                                              //设置文本
	setKeyBord(keyboard.KeyEvent)                                           //设置key bord
}

func (ql *Quadrilateral) SetProps(key, value string) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}

	ql.props.Store(key, value)
	return nil
}

func (ql *Quadrilateral) setKeyBord(event keyboard.KeyEvent) {
	ql.KeyEvent = event
}

func (ql *Quadrilateral) GetKeyBord() (keyboard.KeyEvent, error) {
	if ql.unMount {
		return ql.KeyEvent, errors.New(OperatingEmptyNodeError)
	}

	return ql.KeyEvent, nil
}

func (ql *Quadrilateral) SetText(text string) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	if ql.text != text {
		Render()
		triggerEvent(ql, OnInput, ql)
	}
	ql.text = text
	return nil
}

func (ql *Quadrilateral) Insert(node ...Node) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	ql.children = append(ql.children, node...)
	for _, childNode := range node {
		childNode.setParent(ql)
	}
	Render()
	return nil
}

func (ql *Quadrilateral) setParent(node Node) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}

	oldParent := ql.parent
	if oldParent != nil && node != nil {
		oldStyle, _ := oldParent.GetStyle()
		newStyle, _ := node.GetStyle()
		if oldStyle.Display != newStyle.Display {
			displayEventTrigger(ql, node, newStyle.Display, true)
		}
	} else if oldParent != nil && node == nil {
		displayEventTrigger(ql, nil, false, true)
	} else if oldParent == nil && node != nil {
		newStyle, _ := node.GetStyle()
		if newStyle.Display {
			displayEventTrigger(ql, node, true, true)
		}
	}

	ql.parent = node

	Render()

	if node == nil {
		return errors.New(ParentNodeNil)
	}

	return nil
}

func (ql *Quadrilateral) SetVolume(volume CanvasVolume) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}

	if ql.volume.Width != volume.Width || ql.volume.Height != volume.Height {
		triggerEvent(ql, OnSizeChange, ql)
		Render()
		for _, child := range ql.children { //处理子节点中的自适应数值事件
			autoSizeChangeTrigger(child, ql, true)
		}
	}

	ql.volume = volume
	return nil
}

func (ql *Quadrilateral) SetPosition(position CanvasPosition, pType ...CanvasPositionType) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}

	if position.X != ql.position.X || position.Y != ql.position.Y { //尝试触发事件
		triggerEvent(ql, OnMove, ql)
		for _, child := range ql.children { //处理子节点中的自适应数值事件
			autoSizeChangeTrigger(child, ql, true)
		}
	}

	for _, child := range ql.children {
		autoSizeChangeTrigger(child, ql, true)
	}

	oldPosition := ql.position

	ql.position = CanvasPosition{
		X:      position.X,
		Y:      position.Y,
		totalX: ql.position.totalX,
		totalY: ql.position.totalY,
		Type:   position.Type,
		ZIndex: position.ZIndex,
	}

	typeLen := len(pType)

	if typeLen > 0 {
		ql.position.Type = pType[typeLen-1]
	}

	if !reflect.DeepEqual(oldPosition, ql.position) {
		Render()
	}

	return nil
}

func (ql *Quadrilateral) SetStyle(style CanvasStyle) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	if style.Display != ql.style.Display {
		displayEventTrigger(ql, ql, style.Display, true) //触发显示和隐藏事件，并递归触发
	}

	oldStyle := ql.style
	ql.style = style
	if !reflect.DeepEqual(oldStyle, style) {
		Render()
	}

	return nil
}

func (ql *Quadrilateral) GetVolume() (CanvasVolume, error) {
	if ql.unMount {
		return ql.volume, errors.New(OperatingEmptyNodeError)
	}
	return ql.volume, nil
}

func (ql *Quadrilateral) GetPosition() (CanvasPosition, error) {
	if ql.unMount {
		return ql.position, errors.New(OperatingEmptyNodeError)
	}
	return ql.position, nil
}

func (ql *Quadrilateral) GetStyle() (CanvasStyle, error) {

	if ql.unMount {
		return ql.style, errors.New(OperatingEmptyNodeError)
	}
	return ql.style, nil
}

func (ql *Quadrilateral) GetProps() (map[string]string, error) {
	props := make(map[string]string)

	if ql.unMount {
		return props, errors.New(OperatingEmptyNodeError)
	}

	ql.props.Range(func(key, value any) bool {
		props[key.(string)] = value.(string)
		return true
	})

	return props, nil
}

func (ql *Quadrilateral) AddEventListener(event uint8, callback EventCallBack) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	addEvent(ql, event, callback)
	return nil
}

func (ql *Quadrilateral) DeleteEventListener(event uint8, callback EventCallBack) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	untieEvent(ql, event, callback)
	return nil
}

func (ql *Quadrilateral) GetChildren() ([]Node, error) {
	if ql.unMount {
		return ql.children, errors.New(OperatingEmptyNodeError)
	}
	return ql.children, nil
}

func (ql *Quadrilateral) GetParent() (Node, error) {
	if ql.unMount {
		return ql.parent, errors.New(OperatingEmptyNodeError)
	}
	return ql.parent, nil
}

func (ql *Quadrilateral) RemoveChildren(node Node) error {
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}
	attr, _ := node.GetAttr()
	for index, qlNode := range ql.children {
		if childAttr, _ := qlNode.GetAttr(); childAttr.Key == attr.Key {
			ql.children = append(ql.children[:index], ql.children[index+1:]...)
			if !qlNode.isUnMount() {
				qlNode.Remove()
			}
		}
	}
	return nil
}

func (ql *Quadrilateral) Remove() error { //删除全局引用，不允许再对节点进行操作，但是其特殊点时body不允许删除
	if ql.unMount {
		return errors.New(OperatingEmptyNodeError)
	}

	if ql == Body {
		return errors.New(DeleteTopLeveNodeError)
	}
	nodeParent, _ := ql.GetParent()
	delNodeFromRenderStack(ql)
	delNodeFromNameIndex(ql)
	delNodeFromBase(ql)
	deleteEvent(ql)
	triggerEvent(ql, OnRemove, ql) //触发卸载事件
	if nodeParent != nil && !nodeParent.isUnMount() {
		nodeParent.RemoveChildren(ql)
	}
	ql.unMount = true
	return nil
}

func (ql *Quadrilateral) isUnMount() bool {
	return ql.unMount
}

func (ql *Quadrilateral) GetAttr() (CanvasAttr, error) {
	if ql.unMount {
		return CanvasAttr{}, errors.New(OperatingEmptyNodeError)
	}
	return CanvasAttr{
		Name: ql.name,
		Tag:  ql.tag,
		Key:  ql.key,
	}, nil
}

// RenderZIndexTree 根据RenderStack生成的层级树
type RenderZIndexTree struct {
	nodeBase   []Node
	originBase []Node
}

// GetNode 获取下一个节点
func (rt *RenderZIndexTree) GetNode() (Node, bool) {
	if len(rt.nodeBase) == 0 {
		return nil, false
	} else {
		var miniZIndexNode Node = nil
		var miniIndex = 0

		for index, node := range rt.nodeBase {
			nodePosition, _ := node.GetPosition()
			if miniZIndexNode == nil {
				miniZIndexNode = node
				miniIndex = index
			} else if position, _ := miniZIndexNode.GetPosition(); position.ZIndex > nodePosition.ZIndex {
				miniZIndexNode = node
				miniIndex = index
			}
		}
		rt.nodeBase = append(rt.nodeBase[:miniIndex], rt.nodeBase[miniIndex+1:]...)

		return miniZIndexNode, true
	}
}

func (rt *RenderZIndexTree) Init(nodes NodeStack) {
	rt.nodeBase = make(NodeStack, len(nodes))
	rt.originBase = nodes
	copy(rt.nodeBase, nodes)
}

// PaintingTree 绘画树的接口
type PaintingTree interface {
	GetNode() (Node, bool) //获取下一个节点
	Init(NodeStack)        //初始化
}
